package NBU::Job;
require 5.002;

use strict;
use Carp;

BEGIN {
  use Exporter   ();
  use AutoLoader qw(AUTOLOAD);
  use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);
  $VERSION =     '0.01';
  @ISA =         qw();
  @EXPORT =      qw();
  @EXPORT_OK =   qw();
  %EXPORT_TAGS = qw();
}

my %jobs;

#
# New jobs are registered under their Process IDs
sub new {
  my $Class = shift;
  my $job = {
    MOUNTLIST => {},
  };

  bless $job, $Class;

  if (@_) {
    $job->{PID} = shift;
    if (exists($jobs{$job->pid})) {
      my $pidArray = $jobs{$job->pid};
      push @$pidArray, $job;
    }
    else {
      $jobs{$job->pid} = [ $job ];
    }
  }
  return $job;
}

#
# Extract all job references from the hash and return them
# in a simple array
sub jobList {
  my $Class = shift;

  my @jobList;
  foreach my $pidArray (values %jobs) {
    foreach my $jobR (@$pidArray) {
      push @jobList, $jobR;
    }
  }

  return @jobList;
}

#
# Some jobs turn out to be worse than useless
sub forget {
  my $self = shift;

  if (my $pidArray = $jobs{$self->pid}) {
    my @newArray;
    foreach my $job (@$pidArray) {
      push @newArray, $job unless ($job eq $self);
    }
    if (@newArray < 0) {
      delete $jobs{$self->pid};
    }
    else {
      $jobs{$self->pid} = \@newArray;
    }
  }
}

#
# Returns the last job associated with the argument PID.
sub jobFromPID {
  my $class = shift;
  my $pid = shift;

  if (my $pidArray = $jobs{$pid}) {
    my $job = @$pidArray[@$pidArray - 1];
    if (!defined($job)) {
      print STDERR "Strange doings with pid $pid\n";
    }
    return $job;
  }
  return undef;
} 

sub pid {
  my $self = shift;

  if (@_) {
    $self->{PID} = shift;
  }
  return $self->{PID};
}

sub id {
  my $self = shift;

  if (@_) {
    $self->{ID} = shift;
  }
  return $self->{ID};
}

#
# A job's backup ID really identifies the image that job wrote
# out to the volume(s).
sub backupID {
  my $self = shift;

  if (@_) {
    my $image = NBU::Image->new(shift);
    $self->{IMAGE} = $image;
  }

  return $self->{IMAGE};
}

sub image {
  my $self = shift;

  if (@_) {
    my $image = NBU::Image->new(shift);
    $self->{IMAGE} = $image;
  }

  return $self->{IMAGE};
}

#
# The client and class methods on Job are merely short hand
# for retrieving these attributes from the Job's Image.
sub client {
  my $self = shift;
  my $image = $self->{IMAGE};

  return $image->client;
}

sub class {
  my $self = shift;
  my $image = $self->{IMAGE};

  return $image->class;
}

sub start {
  my $self = shift;

  if (@_) {
    $self->{START} = shift;
  }
  return $self->{START};
}

sub stop {
  my $self = shift;

  if (@_) {
    $self->{STOP} = shift;
    if ($self->active) {
      $self->active->unmount($self->{STOP});
    }
    $self->{STATUS} = shift;
  }
  return $self->{STOP};
}

sub status {
  my $self = shift;

  return $self->{STATUS};
}

sub elapsedTime {
  my $self = shift;

  my $stop = $self->stop;
  $stop = time() if (!$stop);

  return ($stop - $self->start);
}


sub storageUnit {
  my $self = shift;

  if (@_) {
    $self->{STUNIT} = shift;
  }
  return $self->{UNIT};
}

sub mountList {
  my $self = shift;
  my $ml = $self->{MOUNTLIST};

  return %$ml;
}

sub selectMedia {
  my $self = shift;
  my $id = $self->id;
  my $mediaID = shift;
  my $tm = shift;
  my $media;

  if (!($media = NBU::Media->byID($mediaID))) {
    $media = NBU::Media->new($mediaID);
  }

  $media->selected($tm);

  return $self;
}

sub mountMedia {
  my $self = shift;
  my ($mediaID, $driveIndex, $tm)  = @_;

  my $mountListR = $self->{MOUNTLIST};
  my $media = NBU::Media->byID($mediaID);

  my $mount = NBU::Mount->new($self, $media, $driveIndex, $tm);

  $$mountListR{$tm} = $mount;

#  print "Job ".$self->id." ";

  return $self->active($mount);
}

sub active {
  my $self = shift;

  if (@_) {
    $self->{ACTIVE} = shift;
  }
  return $self->{ACTIVE};
}

sub write {
  my $self = shift;
  my ($fragment, $size, $speed) = @_;

  $self->{SIZE} += $size;
  $self->active->write($fragment, $size, $speed);

  return $self;
}

sub ioStats {
  my $self = shift;

  if (@_) {
    my ($noBuffer, $noData, $bytesRead) = @_;

    $self->{NOBUFFER} = $noBuffer;
    $self->{NODATA} = $noData;
  }

  return ($self->{NOBUFFER}, $self->{NODATA}, $self->{SIZE});
}

sub dataWritten {
  my $self = shift;

  return $self->{SIZE};
}

sub printHeader {
  my $self = shift;

  my $pid = $self->pid;
  my $id = $self->id;
  print "Process $pid manages job $id\n";

  return $self;
}

1;

__END__
